/**
 * vue动态创建组件
 * 从远程读取html和js两个文件，创建组件并挂载到某个组件挂载点上
 * //调用例子:
	ComponentUtil.build({
		url : 'example/component', //组件的地址，这个地址上要包含一个作为模板的thml，一个作为组件逻辑的js（可查看example目录）
		reqParam : {param:'这是给子组件的参数'}, //传给子组件的参数
		parentInst: this_ , //父组件vue组件实例
		componentSlot : 'mainUnit', //动态组件挂载的位置，is属性值，默认main 如：<component v-bind:is="main"></component>
		parentCallback:function(res){ //父组件的回调函数，
			console.log('子组件的回复',res);
		}
	});
 */

var ComponentUtil = (function() {
	var inst;
	var obj = (function() {});

	var create = function() {
	    inst = new obj();
	    return inst;
	}
	
	var dialogUrl = '/component/dialog';
	
	obj.prototype.build = function(paras) {
		/** 参数说明
		 * paras.url;		//组件地址，包括相同名字的一个html和一个js
		 * paras.reqParam; 	//传给子组件的参数
		 * paras.parentCallback; //父组件的回调函数
		 * paras.parentInst; //父组件vue组件实例
		 * paras.componentSlot; //组件挂载的位置，默认main
		 * paras.pushState;//boolean型，是否加入历史栈，默认不加
		 */
		var url = Config.baseURL + paras.url; //组件地址，包括相同名字的一个html和一个js
		//动态创建组件并挂载
		var componentName = paras.url; //组件名
		
		var componentObj = eval(Config.vueAppName).component(componentName);
		console.log('devMode:' + Config.devMode +',是否注册过该组件:' + componentName ,!!componentObj);
		/* 非开发模式先从现已注册的注册里查找，如果已注册直接返回 */
		if(Config.devMode == false && !!componentObj){
			createComponent( componentObj , paras);
			return true;
		}
		import( url + '.js?' + new Date().getTime())
			.then(function(module){
				var configObj = module.default;

				//js上的template属性不为空时，不去请求html模板
				if(!configObj.template){
					//获取html模板、创建组件并挂载到父组件上
					axios.request({
						url: url + '.html?' + new Date().getTime(),
					}).then(function (res) {
						configObj.template = res.data;
						createComponent(configObj,paras);
					}).catch(function (err) {
						console.error('html模板页面请求异常:',err);
					});
				}else{
					createComponent(configObj,paras);
				}

		  }).catch(function(err){
				console.log(err);
		  });
	}

	obj.prototype.openDialog = function(paras) {
		inst.build({
			url : dialogUrl,
			parentInst: paras.parentInst ,//父组件vue组件实例
			componentSlot: paras.componentSlot,
			reqParam:{
				url: paras.url,
				dialogParentInst: paras.parentInst,
				dialogComponentSlot: paras.componentSlot,
				title:paras.title,
				width:paras.width,
				reqParam: paras.reqParam
			}
		});
	}
	/* 组件生成 */
	function createComponent(configObj,paras){
		var reqParam = paras.reqParam; //传给子组件的参数
		var parentCallback = paras.parentCallback; //父组件的回调函数
		var parentInst = paras.parentInst; //vue组件实例
		var componentSlot = !paras.componentSlot?'main':paras.componentSlot; //组件挂载的位置。默认main
		var pushState = paras.pushState;//是否加入历史栈，默认不加
		
		var rootApp = eval(Config.vueAppName); //vue应用
		var url = paras.url;
		//组件名
		var componentName = paras.url + '.js';
		/**
		 * 往子组件的data数据里，加入父组件传来的参数
		 * reqParam: 为父组件传递的参数（对象类型），在子组件的data中须保留此属性名，否则会被覆盖
		 **/
		var subData = configObj.data();
		subData.reqParam = reqParam;
		configObj.data = function(){return subData;};
		console.log( componentName + ' 组件参数传递：', reqParam)
		/**
		 * 往子组件的methods中，加入父组件的回调函数
		 * parentCallback: 父组件的回调函数
		 **/
		 if(!!parentCallback && typeof parentCallback == 'function'){
			 configObj.methods.parentCallback = parentCallback;
		 }

		//console.log('component',configObj);
		
		/*
		 * 1、已注册过的组件，不重复注册;
		 */
		var newComponent = eval(Config.vueAppName).component(componentName);
		if( ! newComponent ){
			console.log('注册新组件,','组件名:' + componentName); 
			newComponent = rootApp.component(componentName, configObj);
		}else{
			rootApp._context.components[componentName] = configObj;
		}
		console.log('挂载位置:'+componentSlot,'组件名:'+componentName);
		parentInst[componentSlot] = componentName;
		
		if(pushState==true){
			history.pushState('#'+ url, '', '#'+ url);
		}
		return newComponent;
	}

	//刷新时，自动挂载当前的子组件
	obj.prototype.loadCurrentComponent = function(vm){
		var url = location.hash;
		
		if(!url){
			return false;
		}else{
			url = url.endsWith('/view/login') ? '/view/login' :'/view/main';
		}
		console.log('url',url);
		inst.build({
			url : url,
			parentInst: vm ,//父组件vue组件实例
		});

	}

	//浏览器前进后退处理
	window.onpopstate = function(e) {
		var url = e.state;
		//从应用中获取组件的定义对象，注册并重新挂载
		if(!!url && url!='#' && url.indexOf('#')==0){
			url = url.substring(1)
			var configObj = eval(Config.vueAppName).component(url);
			//console.log(url,configObj);
			if(!!configObj){
				createComponent(configObj,{
					url: url,
					parentInst:eval(Config.vueAppVmName),
					componentSlot:'main'
				});
			}else{
				inst.build({
					url : url,
					parentInst: eval(Config.vueAppVmName),//父组件vue组件实例
				});
			}
		}else{
			location.reload();
		}
	};

	return {
		create: create
	};
})().create();

